/*
 *  circlePanel.cpp
 *  opencvExample
 *
 *  Created by 真鍋 大度 on 11/04/22.
 *  Copyright 2011 Rhizomatiks. All rights reserved.
 *
 */

#include "circlePanel.h"


void circlePanel::setup(int _myID){
	myID = _myID;
	currentMode = MODE_READ;
	bActive = false; // if I am selected(MODE_WRITE) or drawable(MODE_READ)
	bAllCorner = false; 
	//-------XML END	
	message = "loading mySettings " + ofToString(myID, 0) + ".xml";
	
	if( XML.loadFile("mySettings"+ofToString(myID, 0)+".xml") ){
		message = "mySettings.xml loaded!";
	}else{
		message = "unable to load mySettings" + ofToString(myID, 0) + ".xml check data/ folder";
	}
	
	readXML();
	
	//	if (currentMode == MODE_READ) {
	//	}
	//-------XML END
	
	currentFrame = 0;
	
	// interplation
	bInterpol = true;
	numInterpol = 10;;
	
	
}

bool circlePanel::loadMovie(string str){
	if(vidPlayer.loadMovie(str)){
		cout << "myID = " << myID << " load success " << str<< endl;
	}else {
		cout << "myID = " << myID <<"failed "<<endl;
	}
	
	vidPlayer.play();	
	
	w = vidPlayer.getWidth();
	h = vidPlayer.getHeight();
	
	colorImg.allocate(w, h);
	//	cout << "w = " << w << " h = " << h << endl;
	
	centerPt.x = 0.5;
	centerPt.y = 0.5;
	
	// initialize WarpPoint
	numFrames = NUM_FRAMES_WARP;
	for(int i=0;i<numFrames;i++){
		warpCircle tmpWarpPoint;
		ofPoint tmpPtA, tmpPtB, tmpPtC, tmpPtD;
		tmpPtA.set(0, 0);
		tmpPtB.set(w, 0);
		tmpPtC.set(0, h);
		tmpPtD.set(w, h);		
		tmpWarpPoint.setup(tmpPtA, tmpPtB, tmpPtC, tmpPtD);
		tmpWarpPoint.setLoaded(false);
		warpPointList.push_back(tmpWarpPoint);
	}		
	
	
}

void circlePanel::update(int _currentFrame){
	currentFrame = _currentFrame;
	//	currentMode = _currentMode;
	
	setWarpPoint();	
	//warp point interpolation
	//	warpPoint interpPoint;
	//	if (bInterpol) {
	//		//interp calc
	//		interpPoint.set(currentWarpPoint.pt.x - nextWarpPoint.pt.x,
	//	}
	
    bool bNewFrame = false;
	vidPlayer.idleMovie();
	bNewFrame = vidPlayer.isFrameNew();
	if (bNewFrame){
		colorImg.setFromPixels(vidPlayer.getPixels(), w,h);
	}
}


void circlePanel::draw(){
	if (currentMode == MODE_READ) {
		//----		
		//lets make a matrix for openGL
		//this will be the matrix that peforms the transformation
		GLfloat myMatrix[16];
		for(int i = 0; i < 16; i++){
			if(i % 5 != 0) myMatrix[i] = 0.0;
			else myMatrix[i] = 1.0;
		}
		CvPoint2D32f cvsrc[4];
		CvPoint2D32f cvdst[4];	
		cvsrc[0].x = 0;
		cvsrc[0].y = 0;
		cvsrc[1].x = w;
		cvsrc[1].y = 0;
		cvsrc[2].x = w;
		cvsrc[2].y = h;
		cvsrc[3].x = 0;
		cvsrc[3].y = h;			
		for(int i = 0; i < 4; i++){
			cvdst[i].x = warpPointList[currentFrame].pt[i].x;
			cvdst[i].y = warpPointList[currentFrame].pt[i].y;
		}
		
		CvMat * translate = cvCreateMat(3,3,CV_32FC1);
		CvMat* src_mat = cvCreateMat( 4, 2, CV_32FC1 );
		CvMat* dst_mat = cvCreateMat( 4, 2, CV_32FC1 );
		cvSetData( src_mat, cvsrc, sizeof(CvPoint2D32f));
		cvSetData( dst_mat, cvdst, sizeof(CvPoint2D32f));
		cvFindHomography(src_mat, dst_mat, translate);
		float *matrix = translate->data.fl;
		myMatrix[0]		= matrix[0];
		myMatrix[4]		= matrix[1];
		myMatrix[12]	= matrix[2];
		myMatrix[1]		= matrix[3];
		myMatrix[5]		= matrix[4];
		myMatrix[13]	= matrix[5];	
		myMatrix[3]		= matrix[6];
		myMatrix[7]		= matrix[7];
		myMatrix[15]	= matrix[8];	
		
		//finally lets multiply our matrix
		//wooooo hoooo!
		
		ofxMatrix4x4 R = myMatrix;
		glMultMatrixf(R.getPtr());
		//----------変換-------------//		
		if (bActive) {		
			ofSetColor(255, 255, 255);
			warpPointList[currentFrame].draw();
			
			//		ofSetColor(255, 255, 255);
			ofNoFill();
			ofSetRectMode(OF_RECTMODE_CORNER);		
			
			if (warpPointList[currentFrame].bLoaded) {
				ofSetColor(255, 255, 255);			
				colorImg.draw(0, 0);
				// X line		
				ofRect(0, 0, w - 1, h - 1);			
				ofSetColor(5, 250, 0);
				ofLine(0, 0, w-1, h-1);
				ofLine(0, h-1, w-1, 0);		
			}else {			
				ofEnableAlphaBlending();
				ofSetColor(80, 180, 80, 150);
				colorImg.draw(0, 0);
				ofRect(0, 0, w - 1, h - 1);
				// X line		
				ofSetColor(5, 50, 0, 150);
				ofLine(0, 0, w-1, h-1);
				ofLine(0, h-1, w-1, 0);					
			}
		}
		
		//----------変換-------------//				
		ofxMatrix4x4 inversedR;
		inversedR.makeInvertOf(R);
		glMultMatrixf(inversedR.getPtr());		
		//----						
	}
	
	if (currentMode == MODE_WRITE) {
		GLfloat myMatrix[16];
		for(int i = 0; i < 16; i++){
			if(i % 5 != 0) myMatrix[i] = 0.0;
			else myMatrix[i] = 1.0;
		}
		CvPoint2D32f cvsrc[4];
		CvPoint2D32f cvdst[4];	
		cvsrc[0].x = 0;
		cvsrc[0].y = 0;
		cvsrc[1].x = w;
		cvsrc[1].y = 0;
		cvsrc[2].x = w;
		cvsrc[2].y = h;
		cvsrc[3].x = 0;
		cvsrc[3].y = h;			
		for(int i = 0; i < 4; i++){
			cvdst[i].x = corners[i].x  * (float)w;
			cvdst[i].y = corners[i].y * (float) h;
		}
		CvMat * translate = cvCreateMat(3,3,CV_32FC1);
		CvMat* src_mat = cvCreateMat( 4, 2, CV_32FC1 );
		CvMat* dst_mat = cvCreateMat( 4, 2, CV_32FC1 );
		cvSetData( src_mat, cvsrc, sizeof(CvPoint2D32f));
		cvSetData( dst_mat, cvdst, sizeof(CvPoint2D32f));
		cvFindHomography(src_mat, dst_mat, translate);
		float *matrix = translate->data.fl;
		
		myMatrix[0]		= matrix[0];
		myMatrix[4]		= matrix[1];
		myMatrix[12]	= matrix[2];
		
		myMatrix[1]		= matrix[3];
		myMatrix[5]		= matrix[4];
		myMatrix[13]	= matrix[5];	
		
		myMatrix[3]		= matrix[6];
		myMatrix[7]		= matrix[7];
		myMatrix[15]	= matrix[8];	
		
		ofxMatrix4x4 R = myMatrix;
		glMultMatrixf(R.getPtr());
		
		//--アフィン変換したい画像 スタート
		ofEnableAlphaBlending();
		ofNoFill();
		ofSetRectMode(OF_RECTMODE_CORNER);		
		
		if (bActive) {
			ofSetColor(255, 255, 255,255);
		}else {
			ofSetColor(50, 50, 50, 50);
		}	
		colorImg.draw(0, 0);
		
		if (bActive) {
			ofSetColor(255, 0, 0,255);
		}else {
			ofSetColor(100, 0, 0,50);
		}
		ofLine(0, 0, w, h);		
		ofLine(w, 0, 0, h);
		//		franklinBook.drawString(ofToString(myID, 0), 100,100);		
		//--アフィン変換したい画像 エンド	
		
		//逆行列をかけて元に戻す
		ofxMatrix4x4 inversedR;
		inversedR.makeInvertOf(R);		
		glMultMatrixf(inversedR.getPtr());	
		
		ofSetColor(0, 255, 0);		
		
		if (bActive) {
			if (bAllCorner) {
				for(int i=0;i<4;i++){
					ofSetColor(255, 0, 0);
					ofSetRectMode(OF_RECTMODE_CENTER);
					ofRect(corners[i].x * w, corners[i].y * h, 10, 10);
				}
				float centerX = (corners[0].x + corners[1].x + corners[2].x + corners[3].x) / 4.0 * w;
				float centerY = (corners[0].y + corners[1].y + corners[2].y + corners[3].y) / 4.0 * h;									
				ofRect(centerX, centerY, 10, 10);					
			}
			else {
				for(int i=0;i<4;i++){
					if (whichCorner==i) {
						ofSetColor(255, 0, 0);
					}else {
						ofSetColor(0, 255, 60);
					}
					ofSetRectMode(OF_RECTMODE_CENTER);
					ofRect(corners[i].x * w, corners[i].y * h, 10, 10);				
				}
			}
			ofDrawBitmapString(ofToString(myID, 0)+" mode = " + ofToString(currentMode, 0) + " loaded = " + ofToString(warpPointList[currentFrame].bLoaded, 0), corners[0].x * w+10, corners[0].y * h+10);
			
		}
		
		//		ofDrawBitmapString("'s' save, 'r' read status: "+message, 170, 12);
		
	}	
}

//--------------------------------------------------------------
void circlePanel::mouseDragged(int x, int y, int button){
	
	if (bActive) {
		scaleX = (float)x / w;
		scaleY = (float)y / h;
		
		float scaleScreenX = (float)x / ofGetWidth();
		float scaleScreenY = (float)y / ofGetHeight();		
		
		float centerX = (corners[0].x + corners[1].x + corners[2].x + corners[3].x)/4.0f - (float) x / (float) w;
		float centerY = (corners[0].y + corners[1].y + corners[2].y + corners[3].y)/4.0f - (float) y / (float) h;
		
		float deltaX = scaleScreenX - centerX;
		float deltaY = scaleY - centerY;
		
		if (bAllCorner) {
			for (int i=0; i<4; i++) {
				corners[i].x += deltaX;
				corners[i].y += deltaY;					
			}
		}
		else {
			if(whichCorner >= 0 && whichCorner < 4){
				corners[whichCorner].x = scaleX;
				corners[whichCorner].y = scaleY;			
			}			
		}
		
		
	}
	
	
}

//--------------------------------------------------------------
void circlePanel::mousePressed(int x, int y, int button){
	if (bActive) {
		float smallestDist = 1.0;
		whichCorner = -1;
		
		for(int i = 0; i < 4; i++){
			float distx = corners[i].x - (float)x/w;
			float disty = corners[i].y - (float)y/h;
			float dist  = sqrt( distx * distx + disty * disty);
			
			if(dist < smallestDist && dist < 0.1){
				whichCorner = i;
				smallestDist = dist;
			}
			
			//中心を選んだ場合
			
			float distFromCenterX = (corners[0].x + corners[1].x + corners[2].x + corners[3].x)/4.0f - (float)x/w;
			float distFromCenterY = (corners[0].y + corners[1].y + corners[2].y + corners[3].y)/4.0f - (float)y/h;
			float distFromCenter  = sqrt( distFromCenterX * distFromCenterX + distFromCenterY * distFromCenterY);
			if (i==0) {
				cout << "distFromCenter "<<endl;
				cout << distFromCenter <<endl;
			}
			if(distFromCenter < 0.1){
				//				whichCorner = i;
				bAllCorner = true;				
			}
			
			
		}	
		
		for(int i = 0; i < 4; i++){		
			tmpCorners[i] = corners[i];
		}
	}
}

//--------------------------------------------------------------
void circlePanel::mouseReleased(int x, int y, int button){
	whichCorner = -1;
	bAllCorner = false;
}


void circlePanel::readXML(){
	cout << "readXML" << endl;
	//	warpPointList.clear();
	
	//we initalize some of our variables
	lastTagNumber	= 0;
	pointCount		= 0;
	lineCount		= 0;
	
	int numDragTags = XML.getNumTags("STROKE:PT");
	
	if(numDragTags > 0){
		
		XML.pushTag("STROKE", numDragTags-1);
		int numPtTags = XML.getNumTags("PT");
		
		if(numPtTags > 0){
			int totalToRead = MIN(numPtTags, NUM_PTS);
			for(int i = 0; i < totalToRead; i++){
				
				int pframe = XML.getValue("PT:FRAME", -1, i);				
				bool pbactive = XML.getValue("PT:ACTIVE", 0, i) == 1 ? true:false;
				
				int leftTopX = XML.getValue("PT:LTX", 0, i);
				int leftTopY = XML.getValue("PT:LTY", 0, i);
				int leftBottomX = XML.getValue("PT:LBX", w, i);
				int leftBottomY = XML.getValue("PT:LBY", 0, i);
				int rightTopX = XML.getValue("PT:RTX", 0, i);
				int rightTopY = XML.getValue("PT:RTY", h, i);
				int rightBottomX = XML.getValue("PT:RBX", w, i);
				int rightBottomY = XML.getValue("PT:RBY", h, i);
				
				ofPoint tmpA,tmpB,tmpC,tmpD;
				tmpA.set(leftTopX, leftTopY);
				tmpB.set(rightTopX, rightTopY);
				tmpC.set(rightBottomX, rightBottomY);
				tmpD.set(leftBottomX, leftBottomY);			
				
				if (pframe>-1 && pframe<NUM_FRAMES_WARP) {
					warpPointList[pframe].setup(tmpA, tmpB, tmpC, tmpD);
					warpPointList[pframe].setLoaded(pbactive);							
				}
				//				warpPoints[i].setup(tmpA, tmpB, tmpC, tmpD, i);
				
				//				warpPoint tmpWarpPoint;
				//				tmpWarpPoint.setup(tmpA, tmpB, tmpC, tmpD, i);
				//				warpPointList.push_back(tmpWarpPoint);
				
				pointCount++;
			}
		}
		//		numWarp = pointCount;	
		
		//this pops us out of the STROKE tag
		//sets the root back to the xml document
		XML.popTag();
	}else {
		cout << "myID = "<<ofToString(myID, 0) << " = no xml data"<< endl;
	}
	
	
	//------------------     XML shit
	
}

void circlePanel::setPointsToList(){
	ofPoint tmpA,tmpB,tmpC,tmpD;
	tmpA.set(corners[0].x * w, corners[0].y * h);
	tmpB.set(corners[1].x * w, corners[1].y * h);
	tmpC.set(corners[2].x * w, corners[2].y * h);
	tmpD.set(corners[3].x * w, corners[3].y * h);	
	warpPointList[currentFrame].setup(tmpA, tmpB, tmpC, tmpD);	
	warpPointList[currentFrame].setLoaded(true);		
}

void circlePanel::saveXML(){
	
	
	lastTagNumber	= XML.addTag("STROKE");
	xmlStructure	= "<STROKE>\n";
	
	//We start a new stroke
	lineCount		= 0;
	pointCount		= 0;
	
	lastTagNumber	= XML.addTag("STROKE");		
	//We start a new stroke
	lineCount		= 0;
	pointCount		= 0;
	
	//now we will add a pt tag - with two
	//children - X and Y
	if( XML.pushTag("STROKE", lastTagNumber) ){
		
		//now we will add a pt tag - with two
		//children - X and Y
		
		int tagNum = XML.addTag("PT");
		XML.setValue("PT:X", 1, tagNum);
		XML.setValue("PT:Y", 3, tagNum);
		
		XML.popTag();
	}
	
	//	
	//	for (int i=0; i < numFrames; i++) {
	//		if (warpPointList[i].bLoaded) {	
	//		lastTagNumber	= XML.addTag("STROKE");		
	//	
	//			cout << "i " << i << endl; 
	//			if( XML.pushTag("STROKE", lastTagNumber) ){
	//				
	//				//now we will add a pt tag - with two
	//				//children - X and Y
	//				
	//				int tagNum = XML.addTag("PT");
	//				
	//				XML.setValue("PT:FRAME", currentFrame, tagNum);
	//				XML.setValue("PT:ACTIVE", (int)bActive, tagNum);
	//				XML.setValue("PT:LTX", corners[0].x * w, tagNum);
	//				XML.setValue("PT:LTY", corners[0].y * h, tagNum);
	//				XML.setValue("PT:RTX", corners[1].x * w, tagNum);
	//				XML.setValue("PT:RTY", corners[1].y * h, tagNum);
	//				XML.setValue("PT:RBX", corners[2].x * w, tagNum);
	//				XML.setValue("PT:RBY", corners[2].y * h, tagNum);
	//				XML.setValue("PT:LBX", corners[3].x * w, tagNum);
	//				XML.setValue("PT:LBY", corners[3].y * h, tagNum);
	//				XML.popTag();		
	//				
	//			}
	//		}
	//	}
	XML.saveFile("mySettings"+ofToString(myID, 0)+".xml");
	message ="mySettings"+ofToString(myID, 0)+".xml save__!!!";
	cout << ofToString(myID, 0) << " message = "<< message << endl;
	
}



void circlePanel::initXML(){
	XML.clear();	
	lastTagNumber	= XML.addTag("STROKE");
	//We start a new stroke
	lineCount		= 0;
	pointCount		= 0;
	
}

void circlePanel::shift(float _dx, float _dy){
	
	if (bAllCorner) {
		for (int i=0; i<4; i++) {
			corners[i].x += _dx;
			corners[i].y += _dy;			
		}
	}else if(whichCorner >= 0){
		corners[whichCorner].x += _dx;
		corners[whichCorner].y += _dy;			
	}
	
}


void circlePanel::setWarpPoint(){
	int nextFrame;
	if (currentFrame==numFrames-1) {
		nextFrame = numFrames - 1;
	}else {
		nextFrame = currentFrame+1;
	}
	currentWarpPoint = warpPointList[currentFrame];
	nextWarpPoint = warpPointList[nextFrame];
}

void circlePanel::setActive(bool _bActive){
	bActive = _bActive;
}

void circlePanel::toggleActive(){
	bActive = !bActive;
}

//--------------------------------------------------------------
void circlePanel::keyPressed  (int key){
	
	if (bActive) {
		
		if (key == 's') {
			//		saveXML();
			setPointsToList();
		}
		if (key == 'S') {
			//		saveXML();
			saveXML();
		}
		
		if (key == 'r') {
			readXML();
		}
		
		
		if (currentMode == MODE_WRITE) {
			if (key == 'c') {
				initXML();
			}	
			if (key == OF_KEY_LEFT) {
				shift(-0.01,0);
			}
			if (key == OF_KEY_RIGHT) {
				shift(+0.01,0);
			}
			if (key == OF_KEY_UP) {
				shift(0,-0.01);
			}
			if (key == OF_KEY_DOWN) {
				shift(0,0.01);		
			}		
			if(key == '1'){
				whichCorner	= 0;
				bAllCorner = false;
			}
			if (key == '2') {
				whichCorner = 1;	
				bAllCorner = false;
			}
			if (key == '3') {
				whichCorner = 2;	
				bAllCorner = false;
			}
			if (key == '4') {
				whichCorner = 3;	
				bAllCorner = false;
			}
			if (key == '5') {
				bAllCorner = !bAllCorner;
			}
			
		}else if(currentMode==MODE_READ){
		}
		
		if (key == 'm') {
			currentMode++;
			cout << "change mode " << currentMode << endl;
			
			if (currentMode > MODE_NUM-1) {
				currentMode = 0;
			}
			cout << "change mode " << currentMode << endl;
		}
	}	
	
	
}